﻿using System;
using System.Text;

using Microsoft.VisualStudio.TestTools.UnitTesting;
using Evaluant.Uss;
using Evaluant.Uss.Sync;
using Evaluant.Uss.ObjectContext;

namespace NUnit.Sync
{
    [TestClass]
    public class TestSynchronizer
    {

        [TestMethod]
        public void ShouldInstanciate() 
        {
			IPersistenceProvider client = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "Client");
			IPersistenceProvider server = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\NUnit\\Sync\\engines.config", "Server");

            Synchronizer sync = new Synchronizer();
        }

        [TestMethod]
        public void ShouldSerializeMetadata()
        {
			IPersistenceProvider client = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "Client");
			IPersistenceProvider server = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\NUnit\\Sync\\engines.config", "SyncServer");

            IPersistenceEngine pes = server.CreatePersistenceEngine();
            IPersistenceEngine pec = client.CreatePersistenceEngine();

            pes.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pes);
        }

        [TestMethod]
        public void ShouldBulkDownload()
        {
			IPersistenceProvider client = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "Client");
			IPersistenceProvider server = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "Server");

            IPersistenceEngine pes = server.CreatePersistenceEngine();
            IPersistenceEngine pec = client.CreatePersistenceEngine();

            pec.InitializeRepository();
            pes.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pes);

            Synchronizer sync = new Synchronizer();
            sync.Synchronize(pec, pes, SyncDirection.FullDownload, Guid.NewGuid().ToString());

            Assert.AreEqual(3, pec.LoadScalar("count(Person)"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p1'])"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p2'])"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p3'])"));

        }

        [TestMethod]
        public void ShouldSmartDownload()
        {
			IPersistenceProvider client = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "Client");
			IPersistenceProvider server = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncServer");

            IPersistenceEngine pes = server.CreatePersistenceEngine();
            IPersistenceEngine pec = client.CreatePersistenceEngine();

            pes.InitializeRepository();
            pec.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pes);

            Synchronizer sync = new Synchronizer();
            sync.Synchronize(pec, pes, SyncDirection.SmartDownload, Guid.NewGuid().ToString());

            Assert.AreEqual(3, pec.LoadScalar("count(Person)"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p1'])"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p2'])"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p3'])"));
        }

        [TestMethod]
        public void ShouldSmartUpload()
        {
			IPersistenceProvider client = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncClient");
			IPersistenceProvider server = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "Server");

            IPersistenceEngine pes = server.CreatePersistenceEngine();
            IPersistenceEngine pec = client.CreatePersistenceEngine();

            pes.InitializeRepository();
            pec.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");
            
            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");
            
            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");
            
            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pec);

            Synchronizer sync = new Synchronizer();
            sync.Synchronize(pec, pes, SyncDirection.SmartUpload, Guid.NewGuid().ToString());

            Assert.AreEqual(3, pes.LoadScalar("count(Person)"));
            Assert.AreEqual(1, pes.LoadScalar("count(Person[Firstname='p1'])"));
            Assert.AreEqual(1, pes.LoadScalar("count(Person[Firstname='p2'])"));
            Assert.AreEqual(1, pes.LoadScalar("count(Person[Firstname='p3'])"));
        }


        [TestMethod]
        public void ShouldSmartUploadDownload()
        {
			IPersistenceProvider client = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncClient");
			IPersistenceProvider server = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncServer");

            IPersistenceEngine pes = server.CreatePersistenceEngine();
            IPersistenceEngine pec = client.CreatePersistenceEngine();

            pes.InitializeRepository();
            pec.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pes);

            Assert.AreEqual(3, pes.LoadScalar("count(Person)"));

            Entity p4 = new Entity("Person");
            p4.AddValue("Firstname", "p4");

            Entity p5 = new Entity("Person");
            p5.AddValue("Firstname", "p5");

            Entity p6 = new Entity("Person");
            p6.AddValue("Firstname", "p6");

            t = new Transaction();
            t.Serialize(p4);
            t.Serialize(p5);
            t.Serialize(p6);
            t.Commit(pec);

            Assert.AreEqual(3, pec.LoadScalar("count(Person)"));

            Synchronizer sync = new Synchronizer();
            sync.Synchronize(pec, pes, SyncDirection.SmartUploadDownload, Guid.NewGuid().ToString());

            Assert.AreEqual(6, pec.LoadScalar("count(Person)"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p1'])"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p2'])"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p3'])"));

            Assert.AreEqual(6, pes.LoadScalar("count(Person)"));
            Assert.AreEqual(1, pes.LoadScalar("count(Person[Firstname='p4'])"));
            Assert.AreEqual(1, pes.LoadScalar("count(Person[Firstname='p5'])"));
            Assert.AreEqual(1, pes.LoadScalar("count(Person[Firstname='p6'])"));

        }

        [TestMethod]
        public void ShouldSmartUploadDownloadWithTwoClients()
        {
			IPersistenceProvider client = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncClient");
			IPersistenceProvider client2 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncClient2");
			IPersistenceProvider server = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncServer");

            IPersistenceEngine pes = server.CreatePersistenceEngine();
            IPersistenceEngine pec = client.CreatePersistenceEngine();
            IPersistenceEngine pec2 = client2.CreatePersistenceEngine();

            pes.InitializeRepository();
            pec.InitializeRepository();
            pec2.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pes);

            Assert.AreEqual(3, pes.LoadScalar("count(Person)"));

            Entity p4 = new Entity("Person");
            p4.AddValue("Firstname", "p4");

            Entity p5 = new Entity("Person");
            p5.AddValue("Firstname", "p5");

            Entity p6 = new Entity("Person");
            p6.AddValue("Firstname", "p6");

            t = new Transaction();
            t.Serialize(p4);
            t.Serialize(p5);
            t.Serialize(p6);
            t.Commit(pec);

            Assert.AreEqual(3, pec.LoadScalar("count(Person)"));

            Synchronizer sync = new Synchronizer();
            sync.Synchronize(pec, pes, SyncDirection.SmartUploadDownload, Guid.NewGuid().ToString());
            sync.Synchronize(pec2, pes, SyncDirection.SmartUploadDownload, Guid.NewGuid().ToString());

            Assert.AreEqual(6, pec.LoadScalar("count(Person)"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p1'])"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p2'])"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p3'])"));

            Assert.AreEqual(6, pes.LoadScalar("count(Person)"));
            Assert.AreEqual(1, pes.LoadScalar("count(Person[Firstname='p4'])"));
            Assert.AreEqual(1, pes.LoadScalar("count(Person[Firstname='p5'])"));
            Assert.AreEqual(1, pes.LoadScalar("count(Person[Firstname='p6'])"));

            Assert.AreEqual(6, pec2.LoadScalar("count(Person)"));
            Assert.AreEqual(1, pec2.LoadScalar("count(Person[Firstname='p1'])"));
            Assert.AreEqual(1, pec2.LoadScalar("count(Person[Firstname='p2'])"));
            Assert.AreEqual(1, pec2.LoadScalar("count(Person[Firstname='p3'])"));
            Assert.AreEqual(1, pec2.LoadScalar("count(Person[Firstname='p4'])"));
            Assert.AreEqual(1, pec2.LoadScalar("count(Person[Firstname='p5'])"));
            Assert.AreEqual(1, pec2.LoadScalar("count(Person[Firstname='p6'])"));

        }

        [TestMethod]
        public void ShouldResolveConflictByDefault()
        {
			IPersistenceProvider client = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncClient");
			IPersistenceProvider server = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncServer");

            IPersistenceEngine pes = server.CreatePersistenceEngine();
            IPersistenceEngine pec = client.CreatePersistenceEngine();

            pes.InitializeRepository();
            pec.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pes);

            Assert.AreEqual(3, pes.LoadScalar("count(Person)"));

            string clientId = Guid.NewGuid().ToString();

            Synchronizer sync = new Synchronizer();
            sync.Synchronize(pec, pes, SyncDirection.SmartUploadDownload, clientId);

            Assert.AreEqual(3, pec.LoadScalar("count(Person)"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p1'])"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p2'])"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p3'])"));

            Entity p = pec.Load("Person[Firstname='p1']")[0];
            t = new Transaction();
            t.Delete(p);
            t.Commit(pec);

            p = pes.Load("Person[Firstname='p1']")[0];
            p["Firstname"] = "p1 modified";

            t = new Transaction();
            t.Serialize(p);
            t.Commit(pes);

            sync.Synchronize(pec, pes, SyncDirection.SmartUploadDownload, clientId);

            // Check the conflict has been resolved by deleting the Person on the server
            Assert.AreEqual(0, pes.LoadScalar("count(Person[Firstname='p1'])"));

            p = pec.Load("Person[Firstname='p2']")[0];
            t = new Transaction();
            t.Delete(p);
            t.Commit(pec);

            p = pes.Load("Person[Firstname='p2']")[0];
            p["Firstname"] = "p2 modified";

            t = new Transaction();
            t.Serialize(p);
            t.Commit(pes);

            sync.Synchronize(pec, pes, SyncDirection.SmartUploadDownload, clientId);

            // Check the conflict has been resolved by deleting the Person on the client
            Assert.AreEqual(0, pec.LoadScalar("count(Person[Firstname='p1'])"));
        }

        [TestMethod]
        public void ShouldAskForResolution()
        {
			IPersistenceProvider client = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncClient");
			IPersistenceProvider server = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncServer");

            IPersistenceEngine pes = server.CreatePersistenceEngine();
            IPersistenceEngine pec = client.CreatePersistenceEngine();

            pes.InitializeRepository();
            pec.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pes);

            Assert.AreEqual(3, pes.LoadScalar("count(Person)"));

            string clientId = Guid.NewGuid().ToString();

            Synchronizer sync = new Synchronizer();
            sync.Synchronize(pec, pes, SyncDirection.SmartUploadDownload, clientId);

            Assert.AreEqual(3, pec.LoadScalar("count(Person)"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p1'])"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p2'])"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p3'])"));

            Entity p = pec.Load("Person[Firstname='p1']")[0];
            p["Firstname"] = "p1 modified by client";

            t = new Transaction();
            t.Serialize(p);
            t.Commit(pec);

            p = pes.Load("Person[Firstname='p1']")[0];
            p["Firstname"] = "p1 modified by server";

            t = new Transaction();
            t.Serialize(p);
            t.Commit(pes);

            sync.Synchronize(pec, pes, SyncDirection.SmartUploadDownload, clientId);

            // Check the conflict has been resolved by updating the Person on the server
            Assert.AreEqual(1, pes.LoadScalar("count(Person[Firstname='p1 modified by client'])"));

            p = pec.Load("Person[Firstname='p2']")[0];
            p["Firstname"] = "p2 modified by client";

            t = new Transaction();
            t.Serialize(p);
            t.Commit(pec);

            p = pes.Load("Person[Firstname='p2']")[0];
            p["Firstname"] = "p2 modified by server";

            t = new Transaction();
            t.Serialize(p);
            t.Commit(pes);

            sync.Conflict += new ConflictEventHandler(serverWinsResolution);
            sync.Synchronize(pec, pes, SyncDirection.SmartUploadDownload, clientId);

            // Check the conflict has been resolved by updating the Person on the client
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p2 modified by server'])"));
        }

        void serverWinsResolution(object sender, ConflictEventArgs eventArgs)
        {
            eventArgs.Resolution = ConflictResolution.ServerWins;
        }

        [TestMethod]
        public void ShouldSmartUploadDownloadWith3Levels()
        {
            Synchronizer sync = new Synchronizer();

            #region Loads Persistence Providers
			IPersistenceProvider pp1 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "node1");

			IPersistenceProvider pp11 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "node11");

			IPersistenceProvider pp111 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "node111");
			IPersistenceProvider pp112 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "node112");

			IPersistenceProvider pp12 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "node12");

			IPersistenceProvider pp121 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "node121");
			IPersistenceProvider pp122 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "node122");
            #endregion

            #region Loads Persistence Engines
            IPersistenceEngine pe1 = pp1.CreatePersistenceEngine();

            IPersistenceEngine pe11 = pp11.CreatePersistenceEngine();

            IPersistenceEngine pe111 = pp111.CreatePersistenceEngine();
            IPersistenceEngine pe112 = pp112.CreatePersistenceEngine();

            IPersistenceEngine pe12 = pp12.CreatePersistenceEngine();

            IPersistenceEngine pe121 = pp121.CreatePersistenceEngine();
            IPersistenceEngine pe122 = pp122.CreatePersistenceEngine();
            #endregion

            #region Initializes Repositories
            pe1.InitializeRepository();

            pe11.InitializeRepository();

            pe111.InitializeRepository();
            pe112.InitializeRepository();

            pe12.InitializeRepository();

            pe121.InitializeRepository();
            pe122.InitializeRepository();
            #endregion

            // Creates a graph on the top server

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pe1);

            // Updates all sub levels

            sync.Synchronize(pe11, pe1, SyncDirection.SmartUploadDownload);
            sync.Synchronize(pe111, pe11, SyncDirection.SmartUploadDownload);
            sync.Synchronize(pe112, pe11, SyncDirection.SmartUploadDownload);

            sync.Synchronize(pe12, pe1, SyncDirection.SmartUploadDownload);
            sync.Synchronize(pe121, pe12, SyncDirection.SmartUploadDownload);
            sync.Synchronize(pe122, pe12, SyncDirection.SmartUploadDownload);

            // Checks all entities are present on all levels
            foreach (IPersistenceEngine pe in new IPersistenceEngine[] { pe1, pe11, pe12, pe111, pe112, pe121, pe122 })
            {
                Assert.AreEqual(3, pe.LoadScalar("count(Person)"));
                Assert.AreEqual(1, pe.LoadScalar("count(Person[Firstname='p1'])"));
                Assert.AreEqual(1, pe.LoadScalar("count(Person[Firstname='p2'])"));
                Assert.AreEqual(1, pe.LoadScalar("count(Person[Firstname='p3'])"));
            }

            #region Creates an entity on each final client
            
            Entity e = new Entity("Person");
            e.AddValue("Firstname", "e111");

            t = new Transaction();
            t.Serialize(e);
            t.Commit(pe111);

            e = new Entity("Person");
            e.AddValue("Firstname", "e112");

            t = new Transaction();
            t.Serialize(e);
            t.Commit(pe112);

            e = new Entity("Person");
            e.AddValue("Firstname", "e121");

            t = new Transaction();
            t.Serialize(e);
            t.Commit(pe121);

            e = new Entity("Person");
            e.AddValue("Firstname", "e122");

            t = new Transaction();
            t.Serialize(e);
            t.Commit(pe122);

            #endregion

            // Synchronizes all nodes

            sync.Synchronize(pe111, pe11, SyncDirection.SmartUploadDownload);
            Assert.AreEqual(4, pe11.LoadScalar("count(Person)"));
            Assert.AreEqual(4, pe111.LoadScalar("count(Person)"));

            sync.Synchronize(pe112, pe11, SyncDirection.SmartUploadDownload);
            Assert.AreEqual(5, pe11.LoadScalar("count(Person)"));
            Assert.AreEqual(5, pe112.LoadScalar("count(Person)"));

            sync.Synchronize(pe121, pe12, SyncDirection.SmartUploadDownload);
            Assert.AreEqual(4, pe12.LoadScalar("count(Person)"));
            Assert.AreEqual(4, pe121.LoadScalar("count(Person)"));

            sync.Synchronize(pe122, pe12, SyncDirection.SmartUploadDownload);
            Assert.AreEqual(5, pe12.LoadScalar("count(Person)"));
            Assert.AreEqual(5, pe122.LoadScalar("count(Person)"));

            sync.Synchronize(pe11, pe1, SyncDirection.SmartUploadDownload);
            Assert.AreEqual(5, pe1.LoadScalar("count(Person)"));
            Assert.AreEqual(5, pe11.LoadScalar("count(Person)"));

            sync.Synchronize(pe12, pe1, SyncDirection.SmartUploadDownload);
            Assert.AreEqual(7, pe1.LoadScalar("count(Person)"));
            Assert.AreEqual(7, pe12.LoadScalar("count(Person)"));

            sync.Synchronize(pe121, pe12, SyncDirection.SmartUploadDownload);
            Assert.AreEqual(7, pe12.LoadScalar("count(Person)"));
            Assert.AreEqual(7, pe121.LoadScalar("count(Person)"));

            sync.Synchronize(pe122, pe12, SyncDirection.SmartUploadDownload);
            Assert.AreEqual(7, pe12.LoadScalar("count(Person)"));
            Assert.AreEqual(7, pe122.LoadScalar("count(Person)"));

            sync.Synchronize(pe11, pe1, SyncDirection.SmartUploadDownload);
            Assert.AreEqual(7, pe1.LoadScalar("count(Person)"));
            Assert.AreEqual(7, pe11.LoadScalar("count(Person)"));

            sync.Synchronize(pe111, pe11, SyncDirection.SmartUploadDownload);
            Assert.AreEqual(7, pe11.LoadScalar("count(Person)"));
            Assert.AreEqual(7, pe111.LoadScalar("count(Person)"));

            sync.Synchronize(pe112, pe11, SyncDirection.SmartUploadDownload);
            Assert.AreEqual(7, pe11.LoadScalar("count(Person)"));
            Assert.AreEqual(7, pe112.LoadScalar("count(Person)"));

        }

        [TestMethod]
        public void ShouldBulkDownloadAndSmartUpdloadDownload()
        {
            IPersistenceProvider client = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncClient");
            IPersistenceProvider server = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncServer");

            IPersistenceEngine pes = server.CreatePersistenceEngine();
            IPersistenceEngine pec = client.CreatePersistenceEngine();

            pec.InitializeRepository();
            pes.InitializeRepository();

            Entity p1 = new Entity("Person");
            p1.AddValue("Firstname", "p1");

            Entity p2 = new Entity("Person");
            p2.AddValue("Firstname", "p2");

            Entity p3 = new Entity("Person");
            p3.AddValue("Firstname", "p3");

            Transaction t = new Transaction();
            t.Serialize(p1);
            t.Serialize(p2);
            t.Serialize(p3);
            t.Commit(pes);

            Synchronizer sync = new Synchronizer();
            sync.Synchronize(pec, pes, SyncDirection.FullDownload);

            Assert.AreEqual(3, pec.LoadScalar("count(Person)"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p1'])"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p2'])"));
            Assert.AreEqual(1, pec.LoadScalar("count(Person[Firstname='p3'])"));

            Entity p = new Entity("Person");
            p1.AddValue("Firstname", "p");

            t = new Transaction();
            t.Serialize(p);
            t.Commit(pes);

            sync.Synchronize(pec, pes, SyncDirection.SmartUploadDownload);

            Assert.AreEqual(4, pec.LoadScalar("count(Person)"));
        }

		[TestMethod]
		public void DisconnectedMode()
		{
			//	First create entities unmanaged by Euss.Sync
			IPersistenceProvider server = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncServer");
			server.InitializeConfiguration();
			IPersistenceEngine pe_server = server.CreatePersistenceEngine();
			pe_server.InitializeRepository();

			IPersistenceProvider server_nosync = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "Server");
			server_nosync.InitializeConfiguration();
			IPersistenceEngine pe_server_nosync = server_nosync.CreatePersistenceEngine();

			Entity p1 = new Entity("Person");
			p1.AddValue("Firstname", "p1");
			p1.AddValue("Lastname", "P1");

			Entity p2 = new Entity("Person");
			p2.AddValue("Firstname", "p2");
			p2.AddValue("Lastname", "P2");

			Entity p3 = new Entity("Person");
			p3.AddValue("Firstname", "p3");
			p3.AddValue("Lastname", "P3");

			Transaction t = new Transaction();
			t.Serialize(new EntitySet(new Entity[] { p1, p2, p3 }));
			t.Commit(pe_server_nosync);

			pe_server = server.CreatePersistenceEngine();

			//	Create Euss.Sync architecture

			IPersistenceProvider client1 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncClient");
			IPersistenceProvider client2 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncClient2");

			client1.InitializeConfiguration();
			client2.InitializeConfiguration();

			IPersistenceEngine pe_client1 = client1.CreatePersistenceEngine();
			IPersistenceEngine pe_client2 = client2.CreatePersistenceEngine();

			pe_client1.InitializeRepository();
			pe_client2.InitializeRepository();

			Assert.AreEqual(3, pe_server.LoadScalar("count(Person)"));

			//	Get all data using Full Download
			Assert.AreEqual(0, pe_client1.Load("Person").Count);
			Assert.AreEqual(0, pe_client2.Load("Person").Count);

			Synchronizer sync = new Synchronizer();
			sync.Synchronize(pe_client1, pe_server, SyncDirection.FullDownload);
			sync.Synchronize(pe_client2, pe_server, SyncDirection.FullDownload);

			Assert.AreEqual(3, pe_client1.Load("Person").Count);
			Assert.AreEqual(3, pe_client2.Load("Person").Count);

			Entity p = pe_client1.Load("Person[Firstname = 'p1']")[0];
			Assert.IsNotNull(p);
			Assert.AreEqual("P1", p["Lastname"]);

			p = pe_client1.Load("Person[Firstname = 'p2']")[0];
			Assert.IsNotNull(p);
			Assert.AreEqual("P2", p["Lastname"]);

			p = pe_client1.Load("Person[Firstname = 'p3']")[0];
			Assert.IsNotNull(p);
			Assert.AreEqual("P3", p["Lastname"]);

			p = pe_client2.Load("Person[Firstname = 'p1']")[0];
			Assert.IsNotNull(p);
			Assert.AreEqual("P1", p["Lastname"]);

			p = pe_client2.Load("Person[Firstname = 'p2']")[0];
			Assert.IsNotNull(p);
			Assert.AreEqual("P2", p["Lastname"]);

			p = pe_client2.Load("Person[Firstname = 'p3']")[0];
			Assert.IsNotNull(p);
			Assert.AreEqual("P3", p["Lastname"]);

			//	Create an entity in server db and recover it from the 2 clients
			Entity p4 = new Entity("Person");
			p4.AddValue("Firstname", "p4");
			p4.AddValue("Lastname", "P4");

			t = new Transaction();
			t.Serialize(p4);
			t.Commit(pe_server);

			Assert.AreEqual(4, pe_server.Load("Person").Count);

			p = pe_server.Load("Person[Firstname = 'p4']")[0];
			Assert.IsNotNull(p);
			Assert.AreEqual("P4", p["Lastname"]);

			Assert.AreEqual(3, pe_client1.Load("Person").Count);
			Assert.AreEqual(3, pe_client2.Load("Person").Count);

			sync.Synchronize(pe_client1, pe_server, SyncDirection.SmartUploadDownload);
			sync.Synchronize(pe_client2, pe_server, SyncDirection.SmartUploadDownload);

			Assert.AreEqual(4, pe_client1.Load("Person").Count);

			p = pe_client1.Load("Person[Firstname = 'p4']")[0];
			Assert.IsNotNull(p);
			Assert.AreEqual("P4", p["Lastname"]);

			Assert.AreEqual(4, pe_client2.Load("Person").Count);

			p = pe_client2.Load("Person[Firstname = 'p4']")[0];
			Assert.IsNotNull(p);
			Assert.AreEqual("P4", p["Lastname"]);

			//	Create an entity in client 1 and recover it from server and from the client 2
			Entity p5 = new Entity("Person");
			p5.AddValue("Firstname", "p5");
			p5.AddValue("Lastname", "P5");

			t = new Transaction();
			t.Serialize(p5);
			t.Commit(pe_client1);

			Assert.AreEqual(4, pe_server.Load("Person").Count);
			Assert.AreEqual(5, pe_client1.Load("Person").Count);

			p = pe_client1.Load("Person[Firstname = 'p5']")[0];
			Assert.IsNotNull(p);
			Assert.AreEqual("P5", p["Lastname"]);

			Assert.AreEqual(4, pe_client2.Load("Person").Count);

			sync.Synchronize(pe_client1, pe_server, SyncDirection.SmartUploadDownload);

			Assert.AreEqual(5, pe_server.Load("Person").Count);

			p = pe_server.Load("Person[Firstname = 'p5']")[0];
			Assert.IsNotNull(p);
			Assert.AreEqual("P5", p["Lastname"]);

			sync.Synchronize(pe_client2, pe_server, SyncDirection.SmartUploadDownload);

			Assert.AreEqual(5, pe_client1.Load("Person").Count);

			p = pe_client1.Load("Person[Firstname = 'p5']")[0];
			Assert.IsNotNull(p);
			Assert.AreEqual("P5", p["Lastname"]);

			Assert.AreEqual(5, pe_client2.Load("Person").Count);

			p = pe_client2.Load("Person[Firstname = 'p5']")[0];
			Assert.IsNotNull(p);
			Assert.AreEqual("P5", p["Lastname"]);
		}

		[TestMethod]
		public void MultipleTypeSmartUploadDownload()
		{
			IPersistenceProvider server = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncServer");
			server.InitializeConfiguration();
			IPersistenceEngine pe_server = server.CreatePersistenceEngine();
			pe_server.InitializeRepository();

			IPersistenceProvider server_nosync = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "Server");
			server_nosync.InitializeConfiguration();
			IPersistenceEngine pe_server_nosync = server_nosync.CreatePersistenceEngine();

			Entity p1 = new Entity("Person");
			p1.AddValue("Firstname", "p1");
			p1.AddValue("Lastname", "P1");

			Entity p2 = new Entity("Person");
			p2.AddValue("Firstname", "p2");
			p2.AddValue("Lastname", "P2");

			Entity p3 = new Entity("Person");
			p3.AddValue("Firstname", "p3");
			p3.AddValue("Lastname", "P3");

			Transaction t = new Transaction();
			t.Serialize(new EntitySet(new Entity[] { p1, p2, p3 }));
			t.Commit(pe_server_nosync);

			pe_server = server.CreatePersistenceEngine();

			IPersistenceProvider client1 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncClient");

			client1.InitializeConfiguration();

			IPersistenceEngine pe_client1 = client1.CreatePersistenceEngine();

			pe_client1.InitializeRepository();

			Assert.AreEqual(3, pe_server.LoadScalar("count(Person)"));

			//	Get all data using Full Download
			Assert.AreEqual(0, pe_client1.Load("Person").Count);

			Synchronizer sync = new Synchronizer();
			sync.Synchronize(pe_client1, pe_server, SyncDirection.FullDownload);

			Assert.AreEqual(3, pe_client1.Load("Person").Count);

			Entity a1 = new Entity("Address");
			a1.AddValue("City", "Mulhouse");
			a1.AddValue("Street", "Parc Gluck");
			a1.AddValue("PostCode", "68100");
			a1.AddValue("Phone", "0389351919");
			a1.AddValue("Country", "France");

			Entity p4 = new Entity("Person");
			p4.AddValue("Firstname", "p4");
			p4.AddValue("Lastname", "P4");
			p4.AddValue("Address", a1);

			t = new Transaction();
			t.Serialize(p4);
			t.Commit(pe_client1);

			Assert.AreEqual(4, pe_client1.Load("Person").Count);
			Assert.AreEqual(1, pe_client1.Load("Address").Count);

			Assert.AreEqual(3, pe_server.Load("Person").Count);
			Assert.AreEqual(0, pe_server.Load("Address").Count);

			sync.Synchronize(pe_client1, pe_server, SyncDirection.SmartUploadDownload);

			Assert.AreEqual(4, pe_client1.Load("Person").Count);
			Assert.AreEqual(1, pe_client1.Load("Address").Count);

			Assert.AreEqual(4, pe_server.Load("Person").Count);
			Assert.AreEqual(1, pe_server.Load("Address").Count);

			Entity p = pe_server.Load("Person[Firstname = 'p4']")[0];
			Assert.IsNotNull(p);
			Assert.AreEqual(p["Firstname"], "p4");
			Assert.AreEqual(p["Lastname"], "P4");

			pe_server.LoadReference(p, new string[]{ "Address" });

			Entity a = p.GetEntity("Address");
			Assert.IsNotNull(a);
			Assert.AreEqual(a["City"], "Mulhouse");
			Assert.AreEqual(a["Street"], "Parc Gluck");
			Assert.AreEqual(a["PostCode"], "68100");
			Assert.AreEqual(a["Phone"], "0389351919");
			Assert.AreEqual(a["Country"], "France");
		}

		[TestMethod]
		public void Redundunce()
		{
			IPersistenceProvider server = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncServer");
			server.InitializeConfiguration();
			IPersistenceEngine pe_server = server.CreatePersistenceEngine();
			pe_server.InitializeRepository();

			IPersistenceProvider server_nosync = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "Server");
			server_nosync.InitializeConfiguration();
			IPersistenceEngine pe_server_nosync = server_nosync.CreatePersistenceEngine();

			Entity p1 = new Entity("Person");
			p1.AddValue("Firstname", "p1");
			p1.AddValue("Lastname", "P1");

			Entity p2 = new Entity("Person");
			p2.AddValue("Firstname", "p2");
			p2.AddValue("Lastname", "P2");

			Entity p3 = new Entity("Person");
			p3.AddValue("Firstname", "p3");
			p3.AddValue("Lastname", "P3");

			Transaction t = new Transaction();
			t.Serialize(new EntitySet(new Entity[] { p1, p2, p3 }));
			t.Commit(pe_server_nosync);

			pe_server = server.CreatePersistenceEngine();

			IPersistenceProvider client1 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncClient");
			client1.InitializeConfiguration();
			IPersistenceEngine pe_client1 = client1.CreatePersistenceEngine();
			pe_client1.InitializeRepository();

			Assert.AreEqual(3, pe_server.LoadScalar("count(Person)"));
			Assert.AreEqual(0, pe_client1.LoadScalar("count(Person)"));

			Synchronizer sync = new Synchronizer();
			sync.Synchronize(pe_client1, pe_server, SyncDirection.FullDownloadNoBulk);

			Assert.AreEqual(3, pe_server.LoadScalar("count(Person)"));
			Assert.AreEqual(3, pe_client1.LoadScalar("count(Person)"));

			//	Create person on client

			Entity p4 = new Entity("Person");
			p4.AddValue("Firstname", "p4");
			p4.AddValue("Lastname", "p4");

			Entity a1 = new Entity("Address");
			a1.AddValue("City", "Mulhouse");

			p4.AddValue("Address", a1);

			t = new Transaction();
			t.Serialize(p4);
			t.Commit(pe_server);

			Assert.AreEqual(4, pe_server.LoadScalar("count(Person)"));
			Assert.AreEqual(1, pe_server.LoadScalar("count(Address)"));
			Assert.AreEqual(3, pe_client1.LoadScalar("count(Person)"));
			Assert.AreEqual(0, pe_client1.LoadScalar("count(Address)"));

			sync.Synchronize(pe_client1, pe_server, SyncDirection.SmartUploadDownload);

			Assert.AreEqual(4, pe_server.LoadScalar("count(Person)"));
			Assert.AreEqual(1, pe_server.LoadScalar("count(Address)"));
			Assert.AreEqual(4, pe_client1.LoadScalar("count(Person)"));
			Assert.AreEqual(1, pe_client1.LoadScalar("count(Address)"));

			sync.Synchronize(pe_client1, pe_server, SyncDirection.SmartUploadDownload);

			Assert.AreEqual(4, pe_server.LoadScalar("count(Person)"));
			Assert.AreEqual(4, pe_client1.LoadScalar("count(Person)"));
		}

        [TestMethod]
        public void ShouldHandleClientDeleteServerDeleteConflict()
        {
            IPersistenceProvider client1 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncClient");
            IPersistenceProvider client2 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncClient2");
            IPersistenceProvider client3 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncClient3");
            IPersistenceProvider server = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\Nunit\\Sync\\engines.config", "SyncServer");

            IPersistenceEngine pes = server.CreatePersistenceEngine();
            IPersistenceEngine pec1 = client1.CreatePersistenceEngine();
            IPersistenceEngine pec2 = client2.CreatePersistenceEngine();
            IPersistenceEngine pec3 = client3.CreatePersistenceEngine();

            pes.InitializeRepository();
            pec1.InitializeRepository();
            pec2.InitializeRepository();
            pec3.InitializeRepository();

            Entity p = new Entity("Person");
            p.AddValue("Firstname", "p");

            Transaction t = new Transaction();
            t.Serialize(p);
            t.Commit(pes);

            Synchronizer sync = new Synchronizer();
            sync.Synchronize(pec1, pes, SyncDirection.FullDownloadNoBulk);
            sync.Synchronize(pec2, pes, SyncDirection.FullDownloadNoBulk);
            sync.Synchronize(pec3, pes, SyncDirection.FullDownloadNoBulk);

            Assert.AreEqual(1, pec1.Load("Person[Firstname='p']").Count);
            Assert.AreEqual(1, pec2.Load("Person[Firstname='p']").Count);
            Assert.AreEqual(1, pec3.Load("Person[Firstname='p']").Count);

            // Concurrent deletion on two clients

            p = pec1.Load("Person[Firstname='p']")[0];

            t = new Transaction();
            t.Delete(p);
            t.Commit(pec1);

            sync.Synchronize(pec1, pes, SyncDirection.SmartUploadDownload);

            p = pec2.Load("Person[Firstname='p']")[0];

            t = new Transaction();
            t.Delete(p);
            t.Commit(pec2);

            sync.Synchronize(pec2, pes, SyncDirection.SmartUploadDownload);

            // Updates the third client, which should delete the entity

            sync.Synchronize(pec3, pes, SyncDirection.SmartUploadDownload);

            Assert.AreEqual(0, pec3.Load("Person").Count);

        }

        [TestMethod]
        public void ShouldHandleClientCreateClientDeleteConflict()
        {
            // TODO: ne passe pas car les optimized inversent l'ordre (delete passé avant le create)

			IPersistenceProvider client1 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\NUnit\\Sync\\engines.config", "SyncClient");
			IPersistenceProvider client2 = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\NUnit\\Sync\\engines.config", "SyncClient2");
			IPersistenceProvider server = XmlConfigLoader.LoadXmlConfig("..\\..\\..\\NUnit\\Sync\\engines.config", "SyncServer");

            IPersistenceEngine pes = server.CreatePersistenceEngine();
            IPersistenceEngine pec1 = client1.CreatePersistenceEngine();
            IPersistenceEngine pec2 = client2.CreatePersistenceEngine();

            pes.InitializeRepository();
            pec1.InitializeRepository();
            pec2.InitializeRepository();

            Entity p = new Entity("Person");
            p.AddValue("Firstname", "p");

            Transaction t = new Transaction();
            t.Serialize(p);
            t.Commit(pec1);

            Assert.AreEqual(1, pec1.Load("Person[Firstname='p']").Count);

            p = pec1.Load("Person[Firstname='p']")[0];

            t = new Transaction();
            t.Delete(p);
            t.Commit(pec1);

            Synchronizer sync = new Synchronizer();
            sync.Synchronize(pec1, pes, SyncDirection.SmartUploadDownload);
            sync.Synchronize(pec2, pes, SyncDirection.SmartUploadDownload);

            Assert.AreEqual(0, pec2.Load("Person").Count);

        }


        [TestMethod]
        public void GE_DuplicatedKeys()
        {
            ObjectService os = new ObjectService("..\\..\\..\\Nunit\\Sync\\engines.config", "BEL_REF_SERVER");
            ObjectContext belRefServer = os.CreateObjectContext();

            os = new ObjectService("..\\..\\..\\Nunit\\Sync\\engines.config", "GLA_BAK_SERVER");
            ObjectContext glaBakServer = os.CreateObjectContext();

            belRefServer.InitializeRepository();
            glaBakServer.InitializeRepository();

            Person p1 = new Person();
            p1.Lastname = "Pfeffer";
            p1.Firstname = "Sébastien";
            p1.PersonId = "p1";

            glaBakServer.BeginTransaction();
            glaBakServer.Serialize(p1);
            glaBakServer.CommitTransaction();

            Person p = glaBakServer.LoadWithId<Person>("p1");
            Assert.IsNotNull(p);
            Assert.AreEqual("Sébastien", p.Firstname);

            glaBakServer.BeginTransaction();
            glaBakServer.Delete(p1);
            glaBakServer.CommitTransaction();

            glaBakServer.Clear();

            p1.Firstname = "Jaroslaw";

            glaBakServer.BeginTransaction();
            glaBakServer.Serialize(p1);
            glaBakServer.CommitTransaction();

            p = glaBakServer.LoadWithId<Person>("p1");
            Assert.IsNotNull(p);
            Assert.AreEqual("Jaroslaw", p.Firstname);

            Synchronizer sync = new Synchronizer();
            sync.Synchronize(glaBakServer.PersistenceEngine, belRefServer.PersistenceEngine, SyncDirection.SmartUpload, Guid.NewGuid().ToString());

            p = belRefServer.LoadWithId<Person>("p1");
            Assert.IsNotNull(p);
            Assert.AreEqual("Jaroslaw", p.Firstname);
        }
    }
}
